/*
 * Copyright (c) 2022 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "hks_useridm_api_wrap.h"
#include "user_idm_client.h"

#include "hks_condition.h"
#include "hks_log.h"
#include "hks_mem.h"

#define USER_IAM OHOS::UserIam::UserAuth

static int32_t ConvertFromHksAuthType(enum HksUserAuthType hksAuthType, enum USER_IAM::AuthType *authType)
{
    switch (hksAuthType) {
        case HKS_USER_AUTH_TYPE_FACE:
            *authType = USER_IAM::AuthType::FACE;
            break;
        case HKS_USER_AUTH_TYPE_PIN:
            *authType = USER_IAM::AuthType::PIN;
            break;
        case HKS_USER_AUTH_TYPE_FINGERPRINT:
            *authType = USER_IAM::AuthType::FINGERPRINT;
            break;
        default:
            HKS_LOG_E("Invalid hksAuthType!");
            return HKS_FAILURE; // 如果异常值，没有对应authtype （也不需要）
    }
    return HKS_SUCCESS;
}

static int32_t ConvertToHksAuthType(enum USER_IAM::AuthType authType, enum HksUserAuthType *hksAuthType)
{
    switch (authType) {
        case USER_IAM::AuthType::FACE:
            *hksAuthType = HKS_USER_AUTH_TYPE_FACE;
            break;
        case USER_IAM::AuthType::PIN:
            *hksAuthType =  HKS_USER_AUTH_TYPE_PIN;
            break;
        case USER_IAM::AuthType::FINGERPRINT:
            *hksAuthType =  HKS_USER_AUTH_TYPE_FINGERPRINT;
        default:
            HKS_LOG_E("Invalid authType!");
            return HKS_FAILURE; // AuthType::ALL的情况尚未考虑（不需考虑，all只用于查询指定）；  如果枚举指纹，没有对应authtype 
    }
    return HKS_SUCCESS;
}

class GetSecUserInfoCallbackImplHuks: public USER_IAM::GetSecUserInfoCallback {
public:
    GetSecUserInfoCallbackImplHuks(struct SecInfoWrap **mOutSecInfo, HksCondition *mCondition):outSecInfo(mOutSecInfo), condition(mCondition) {}
    virtual ~GetSecUserInfoCallbackImplHuks() = default;
    void OnSecUserInfo(const USER_IAM::SecUserInfo &info) override;
    volatile bool isCallbacked = false;

private:
    struct SecInfoWrap **outSecInfo;
    HksCondition *condition;
};

void GetSecUserInfoCallbackImplHuks::OnSecUserInfo(const USER_IAM::SecUserInfo &info) {
        int32_t ret = HKS_SUCCESS;
        do {
            uint32_t secInfoSize = sizeof(struct SecInfoWrap) + ((info.enrolledInfo.size() > DEFAULT_ENROLLED_INFO_LEN) ? 
               sizeof(struct EnrolledInfoWrap) * (info.enrolledInfo.size() - DEFAULT_ENROLLED_INFO_LEN) : 0);
            *outSecInfo = (struct SecInfoWrap *)HksMalloc(secInfoSize);
            if (*outSecInfo == NULL) {
                HKS_LOG_E("Malloc enrolledInfo failed!");
                ret = HKS_ERROR_MALLOC_FAIL;
                break;
            }

            (**outSecInfo).secureUid = info.secureUid;
            (**outSecInfo).enrolledInfoLen = info.enrolledInfo.size();
            for (uint32_t i = 0; i<(**outSecInfo).enrolledInfoLen; ++i) {
                enum HksUserAuthType authType;
                ret = ConvertToHksAuthType(info.enrolledInfo[i].authType, &authType);
                if (ret != HKS_SUCCESS) {
                    HKS_LOG_E("ConvertToHksAuthType failed :%d!", ret);
                    break;
                }
                (**outSecInfo).enrolledInfo[i].authType = authType;
                
                (**outSecInfo).enrolledInfo[i].enrolledId = info.enrolledInfo[i].enrolledId;
            }
            HKS_LOG_E("GetSecInfoCallback num: %d.", (**outSecInfo).enrolledInfoLen);
        } while(0);
        HKS_LOG_E("GetSecUserInfoCallbackImplHuks 3");
        if (ret != HKS_SUCCESS) {
            HksFree(*outSecInfo);
            *outSecInfo = NULL;
        }
        isCallbacked = true;
        HksConditionNotify(condition);
}

int32_t HksUserIdmGetSecInfo(int32_t userId, struct SecInfoWrap **outSecInfo)
{
    if (outSecInfo == NULL) {
        HKS_LOG_E("HksUserIdmGetSecInfo arguments invalid!");
        return HKS_ERROR_INVALID_ARGUMENT;
    }

    HksCondition *condition= HksConditionCreate();

    if (condition == NULL) {
        HKS_LOG_E("create condition failed!");
        return HKS_FAILURE;
    }

    auto mCallback = std::make_shared<GetSecUserInfoCallbackImplHuks>(outSecInfo, condition);
    if (mCallback != nullptr) {
        HKS_LOG_E("std::make_shared<GetSecUserInfoCallbackImpl>");
        // to be deleted
    }

    std::shared_ptr<USER_IAM::GetSecUserInfoCallback> callback = mCallback;

    userId = 100; ///// 打桩

    HKS_LOG_E("userId: %d", userId);
    int32_t ret = USER_IAM::UserIdmClient::GetInstance().GetSecUserInfo(userId, callback);
    
    if (ret == USER_IAM::ResultCode::SUCCESS) {
        while(!(*mCallback).isCallbacked) {
            HksConditionWait(condition);
        }
        //打桩测试
        if ((*outSecInfo)->enrolledInfoLen == 0) {
            (*outSecInfo)->enrolledInfoLen = 1;
            (*outSecInfo)->secureUid = 0;
            (*outSecInfo)->enrolledInfo[0].authType = HKS_USER_AUTH_TYPE_PIN;
            (*outSecInfo)->enrolledInfo[0].enrolledId = 0;
        }
    } else {
        HKS_LOG_E("GetSecInfoCallback failed: %d!", ret);
        *outSecInfo = (struct SecInfoWrap *)HksMalloc(sizeof(struct SecInfoWrap));
        // (*outSecInfo)->enrolledInfoLen = 0;
        // (*outSecInfo)->secureUid = 0;
        //打桩测试
        (*outSecInfo)->enrolledInfoLen = 1;
        (*outSecInfo)->secureUid = 0;
        (*outSecInfo)->enrolledInfo[0].authType = HKS_USER_AUTH_TYPE_PIN;
        (*outSecInfo)->enrolledInfo[0].enrolledId = 0;
    }
    
    HksConditionDestroy(condition);
    
    if (*outSecInfo == NULL) {
        HKS_LOG_E("get sec info failed!");
        return HKS_FAILURE;
    }
    return HKS_SUCCESS;
}

class GetCredentialInfoCallbackImplHuks:public USER_IAM::GetCredentialInfoCallback {
public:
    GetCredentialInfoCallbackImplHuks(int32_t *mNumOfAuthInfo, HksCondition *mCondition):numOfAuthInfo(mNumOfAuthInfo),condition(mCondition)
    {

    }
    virtual ~GetCredentialInfoCallbackImplHuks(){}

    volatile bool isCallbacked = false;
    void OnCredentialInfo(const std::vector<USER_IAM::CredentialInfo> &infoList) {
        *numOfAuthInfo = infoList.size();

        HKS_LOG_E("GetCredentialInfoCallback num: %d.", *numOfAuthInfo);

        isCallbacked = true;
        HksConditionNotify(condition);
    }
private:
    int32_t *numOfAuthInfo;
    HksCondition *condition;
};

int32_t HksUserIdmGetAuthInfoNum(int32_t userId, enum HksUserAuthType hksAuthType, int32_t *numOfAuthInfo)
{
    if (numOfAuthInfo == NULL) {
        HKS_LOG_E("HksGetAuthInfo arguments invalid!");
        return HKS_ERROR_INVALID_ARGUMENT;
    }
    *numOfAuthInfo = 0;

    HksCondition *condition= HksConditionCreate();
    if (condition == NULL) {
        HKS_LOG_E("create condition failed!");
        return HKS_FAILURE;
    }
    
    auto mCallback = std::make_shared<GetCredentialInfoCallbackImplHuks>(numOfAuthInfo, condition);
    std::shared_ptr<USER_IAM::GetCredentialInfoCallback> callback = mCallback;

    enum USER_IAM::AuthType authType;

    int32_t ret = ConvertFromHksAuthType(hksAuthType, &authType);
    if (ret != HKS_SUCCESS) {
        HKS_LOG_E("ConvertFromHksAuthType failed: %d!", ret);
        return ret;
    }

    userId = 100; ///// 打桩
    // 需要 ohos.permission.MANAGE_USER_IDM 权限
    ret = USER_IAM::UserIdmClient::GetInstance().GetCredentialInfo(userId, authType, callback);

    if (ret == USER_IAM::ResultCode::SUCCESS) {
        while(!(*mCallback).isCallbacked) {
            HksConditionWait(condition);
        }
        // 打桩测试
        if (*numOfAuthInfo == 0) {
            *numOfAuthInfo = 1;
        }
    } else {
        HKS_LOG_E("GetAuthInfo failed: %d!", ret);
        // *numOfAuthInfo == 0;
        // 打桩测试
        if (*numOfAuthInfo == 0) {
            *numOfAuthInfo = 1;
        }
    }
    
    HksConditionDestroy(condition);

    return HKS_SUCCESS;
}

int32_t HksConvertUserIamTypeToHksType(enum HksUserIamType type, uint32_t userIamValue, uint32_t *hksValue)
{
    if (hksValue == nullptr) {
        return HKS_ERROR_NULL_POINTER;
    }

    switch (type) {
        case HKS_AUTH_TYPE:
            return ConvertToHksAuthType((enum USER_IAM::AuthType)userIamValue, (enum HksUserAuthType *)hksValue);
        default:
            break;
    }
    return HKS_ERROR_NOT_SUPPORTED;
}
